﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using PServiceBus.Core.Manager;
using System.Text.RegularExpressions;
using PServiceBus.Core.Runtime.Topics;

namespace PServiceBus.Core.Runtime.Extensions {
    public static class SubscriberExtension {
        /// <summary>
        /// Get Message Filter by topicID
        /// </summary>
        /// <param name="topicID"></param>
        /// <returns></returns>
        public static Tuple<string, bool> GetMessageFilter(this ISubscriber subscriber, Guid topicID) {
            var subscription = subscriber.Subscriptions.Where(s => s.ID == topicID).FirstOrDefault();
            return !subscription.IsEmpty() ? new Tuple<string, bool>(subscription.MessageFilter, subscription.CaseSensitive) : 
                new Tuple<string,bool>(string.Empty, false);
        }

        /// <summary>
        /// Remove subscriber from underlying data store
        /// </summary>
        /// <param name="subscriber"></param>
        public static void Delete(this ISubscriber subscriber) {
            SubscriberManager.Invoke(provider => provider.Delete(subscriber));
        }

        /// <summary>
        /// Save subscriber to underlying data store
        /// </summary>
        /// <param name="subscriber"></param>
        public static void Save(this ISubscriber subscriber) {
            SubscriberManager.Invoke(provider => provider.Add(subscriber));
        }

        public static void Refresh(this ISubscriber subscriber) {
            SubscriberManager.Invoke(provider => provider.Refresh(subscriber));
        }

        /// <summary>
        /// Gets a value indicating whether this subscription is empty.
        /// </summary>
        /// <value><c>true</c> if this subscription is empty; otherwise, <c>false</c>.</value>
        public static bool IsEmpty(this SubscriptionEntry subscriptionInfo) {
            return subscriptionInfo.ID == Guid.Empty && subscriptionInfo.MessageFilter == null;
        }

        private static string CreateWildCardRegex(string name) {
            var splitDelimeter = string.Empty;
            var tokens = name.Split('.');
            if (tokens.Length > 0) splitDelimeter = @"\.{1}";
            else {
                tokens = name.Split('/');
                splitDelimeter = @"\/{1}";
            }
            var regex = new StringBuilder();
            for (var i = 0; i < tokens.Length; i++) {
                regex.AppendFormat("{0}({1})", i == 0 ? "^" : string.Empty,
                    tokens[i] == "*" ? "(.+)" : tokens[i]);
                if (i != tokens.Length - 1) regex.Append(splitDelimeter);
            }
            regex.Append("$");
            return regex.ToString();
        }

        /// <summary>
        /// Return true if subscriber is subscribed to specified topic id
        /// </summary>
        /// <param name="topicID">The specified topic</param>
        /// <returns>true if subscribed</returns>
        public static bool IsSubscribedTo(this ISubscriber subscriber, Guid topicID, out Guid selectTopicID) {
            var hasSubscription = subscriber.Subscriptions.Any(s => s.ID == topicID);
            var wildCardTopics = !hasSubscription ? subscriber.Subscriptions.Where(x => x.IsWildCard)
                .Select(x => x.TopicName) : new List<string>();
            if (wildCardTopics.Any()) {
                var topic = TopicManager.Current.GetTopic(topicID);
                if (topic != null) {
                    var topicName = topic.Name;
                    foreach (var wildCard in wildCardTopics)
                        if (Regex.IsMatch(topicName, CreateWildCardRegex(wildCard))) {
                            selectTopicID = TopicManager.Current.GetTopic(wildCard).ID;
                            return true;
                        }
                }
            }
            selectTopicID = topicID;
            return hasSubscription;
        }
    }
}
